import { CryptoJS } from '@ohos/crypto-js';
import { ByteUtils } from './ByteUtils';

export class DesUtils {
    constructor() {
        this.ZERO_IVC = ByteUtils.hexStrToBytes("0000000000000000");
    }

    pboc3desMAC(data, key, iv) {
        console.log("pboc3desMAC --------");

        console.log(ByteUtils.bytesToHexStr(data))
        console.log(ByteUtils.bytesToHexStr(key))
        console.log(ByteUtils.bytesToHexStr(iv));

        let leftKey = key.slice(0, 8);
        // 拆分数据（8字节块/Block）
        let dataLength = data.length;
        let blockCount = parseInt(dataLength / 8 + 1);
        let lastBlockLength = parseInt(dataLength % 8);

        console.log(dataLength, blockCount, lastBlockLength);

        let dataBlock = Array();
        for (let i = 0; i < blockCount; i++) {
            let copyLength = i === blockCount - 1 ? lastBlockLength : 8;
            let temp = data.slice(i * 8, i * 8 + copyLength);
            temp = ByteUtils.bytesToHexStr(temp);
            while (temp.length < 16) {
                temp += "0";
            }
            dataBlock.push(ByteUtils.hexStrToBytes(temp));
        }
        dataBlock[blockCount - 1][lastBlockLength] = 0x80;

        for (let i = 0; i < blockCount; i++) {
            console.log("dataBlock = " + i, ByteUtils.bytesToHexStr(dataBlock[i]));
        }

        let desXor = this.xOr(dataBlock[0], iv);
        for (let i = 1; i < blockCount; i++) {
            let des = this.encryptDES_CBC(desXor, leftKey, this.ZERO_IVC);
            desXor = this.xOr(dataBlock[i], ByteUtils.hexStrToBytes(des));
        }
        return this.encrypt3DES_CBC(desXor, key, this.ZERO_IVC);
        // return desXor;
    }


    xOr(b1, b2) {
        let tXor = new Uint8Array(new ArrayBuffer(Math.min(b1.length, b2.length)));
        for (let i = 0; i < tXor.length; i++) {
            tXor[i] = b1[i] ^ b2[i]; // 异或(Xor)
        }
        return tXor;
    }

    encryptDES_CBC(data, key, iv) {
        var keyHex = ByteUtils.bytesToHexStr(key);
        var ivHex = ByteUtils.bytesToHexStr(iv);
        var dataHex = ByteUtils.bytesToHexStr(data);

        console.log("encryptDES_CBC", dataHex, keyHex, ivHex);
        var encrypted = CryptoJS.DES.encrypt(
            CryptoJS.enc.Hex.parse(dataHex),
            CryptoJS.enc.Hex.parse(keyHex), {
            iv: CryptoJS.enc.Hex.parse(ivHex),
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.NoPadding
        });
        var encryptedHex = encrypted.ciphertext.toString();
        console.log("result = ", encryptedHex);
        return encryptedHex;
    }

    decryptDES_CBC(data, key, iv) {
        var keyHex = ByteUtils.bytesToHexStr(key);
        var ivHex = ByteUtils.bytesToHexStr(iv);
        var dataHex = ByteUtils.bytesToHexStr(data);

        console.log("decryptDES_CBC", dataHex, keyHex, ivHex);
        var decrypted = CryptoJS.DES.decrypt(
            { ciphertext: CryptoJS.enc.Hex.parse(dataHex) },
            CryptoJS.enc.Hex.parse(keyHex), {
            iv: CryptoJS.enc.Hex.parse(ivHex),
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.NoPadding
        });
        var decryptedHex = decrypted.toString()
        console.log("result = ", decryptedHex);
        return decryptedHex;
    }

    encrypt3DES_CBC(data, key, iv) {
        var keyHex = ByteUtils.bytesToHexStr(key);
        var ivHex = ByteUtils.bytesToHexStr(iv);
        var dataHex = ByteUtils.bytesToHexStr(data);
        console.log("encrypt3DES_CBC", dataHex, keyHex, ivHex);
        var encrypted = CryptoJS.TripleDES.encrypt(
            CryptoJS.enc.Hex.parse(dataHex),
            CryptoJS.enc.Hex.parse(keyHex), {
            iv: CryptoJS.enc.Hex.parse(ivHex),
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.NoPadding
        });
        var encryptedHex = encrypted.ciphertext.toString();
        // var key = TripleDESUtils.convertKeySync(key)
        // var encrypted = TripleDESUtils.encryptSync(key,data,"3DES192|CBC|NoPadding","0000000000000000")
        // console.log("result = ", ByteUtils.bytesToHexStr(encrypted));
        return encryptedHex;
    }
}
